package com.hundsun.cprs.yyt.service.account.service.impl;

import com.hundsun.cprs.yyt.common.base.BaseService;
import com.hundsun.cprs.yyt.common.enums.EnumBusinessCode;
import com.hundsun.cprs.yyt.common.exception.ServiceCodeException;
import com.hundsun.cprs.yyt.common.redis.RedisDistributedLock;
import com.hundsun.cprs.yyt.service.account.domain.query.AccountQuotaLogQuery;
import com.hundsun.cprs.yyt.service.account.enums.EnumQuotaTransType;
import com.hundsun.cprs.yyt.service.account.service.AccountDailyLimitCacheService;
import com.hundsun.cprs.yyt.service.common.Constants;
import com.hundsun.cprs.yyt.service.system.enums.EnumBussinessParam;
import com.hundsun.cprs.yyt.service.system.service.BusinessParamHelper;
import com.hundsun.cprs.yyt.service.system.service.BussinessParamService;
import com.hundsun.cprs.yyt.service.trade.domain.TradeEntrust;
import com.hundsun.cprs.yyt.service.trade.domain.query.TradeEntrustQuery;
import com.hundsun.cprs.yyt.service.trade.service.TradeEntrustService;
import com.hundsun.cprs.yyt.util.DateUtil;
import com.hundsun.cprs.yyt.util.DoubleUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.util.Date;
import java.util.Map;

@Service
public class AccountDailyLimitCacheServiceImpl extends BaseService implements AccountDailyLimitCacheService {

    /** 用户每日挂售数量计数器 */
    public static final String YYT_SELL_AMOUNT_COUNT = Constants.YYT_SELL_AMOUNT_COUNT;
    /** 用户每日挂售数量记录锁 */
    public static final String YYT_SELL_AMOUNT_LOCK = Constants.YYT_SELL_AMOUNT_LOCK;
    /** 用户每日挂售金额汇总计数器 */
    public static final String YYT_SELL_MONEY_COUNT = Constants.YYT_SELL_MONEY_COUNT;
    /** 用户每日挂售金额汇总记录锁 */
    public static final String YYT_SELL_MONEY_LOCK = Constants.YYT_SELL_MONEY_LOCK;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private RedisDistributedLock redisLock;
    @Autowired
    private BussinessParamService bussinessParamService;
    @Autowired
    private TradeEntrustService tradeEntrustService;

    @Override
    public void addUserSellAmountToCache(TradeEntrust tradeEntrust) {
        String createLockKey = MessageFormat.format(YYT_SELL_AMOUNT_LOCK,tradeEntrust.getUserId());
        String cacheKey = YYT_SELL_AMOUNT_COUNT;
        try{
            //获取创建锁,竞争则等待
            if(redisLock.lock(createLockKey)){
                BoundZSetOperations<String,Object> zSetOper = redisTemplate.boundZSetOps(cacheKey);
                if (redisTemplate.hasKey(cacheKey)){
                    Double count = zSetOper.score(tradeEntrust.getUserId());
                    if (count != null){
                        count = DoubleUtil.add(count,1L);
                        zSetOper.add(tradeEntrust.getUserId(),count);
                    }else{
                        initUserEntrustTimeCache(cacheKey,tradeEntrust.getUserId(),1L);
                        //zSetOper.add(tradeEntrust.getUserId(),1L);
                    }
                }else{
                    //不存在则初始化用户每日挂售次数计数器
                    initUserEntrustTimeCache(cacheKey,tradeEntrust.getUserId(),1L);
                    //zSetOper.add(tradeEntrust.getUserId(),1L);
                    //设置缓存的过期时间为当天
                    //zSetOper.expireAt(DateUtil.getEndOfDay(new Date()));
                }
            }else{
                throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1000.getErrorNo(), "无法获取用户用户每日挂售数量记录锁[" + tradeEntrust.getUserId() + "]");
            }
        }finally{
            redisLock.releaseLock(createLockKey);
        }
    }

    @Override
    public void addUserSellMoneyToCache(TradeEntrust tradeEntrust) {
        String createLockKey = MessageFormat.format(YYT_SELL_MONEY_LOCK,tradeEntrust.getUserId());
        String cacheKey = YYT_SELL_MONEY_COUNT;
        try{
            //获取创建锁,竞争则等待
            if(redisLock.lock(createLockKey)){
                BoundZSetOperations<String,Object> zSetOper = redisTemplate.boundZSetOps(cacheKey);
                if (redisTemplate.hasKey(cacheKey)){
                    Double count = zSetOper.score(tradeEntrust.getUserId());
                    if (count != null){
                        count = DoubleUtil.add(count,tradeEntrust.getEntrustAmount()*tradeEntrust.getEntrustPrice());
                        zSetOper.add(tradeEntrust.getUserId(),count);
                    }else{
                        initUserEntrustMoneyCache(cacheKey,tradeEntrust.getUserId(),tradeEntrust.getEntrustAmount()*tradeEntrust.getEntrustPrice());
                        //zSetOper.add(tradeEntrust.getUserId(),tradeEntrust.getEntrustAmount()*tradeEntrust.getEntrustPrice());
                    }
                }else{
                    //不存在则初始化用户每日挂售金额汇总计数器
                    initUserEntrustMoneyCache(cacheKey,tradeEntrust.getUserId(),tradeEntrust.getEntrustAmount()*tradeEntrust.getEntrustPrice());
                    //zSetOper.add(tradeEntrust.getUserId(),tradeEntrust.getEntrustAmount()*tradeEntrust.getEntrustPrice());
                    //设置缓存的过期时间为当天
                    //zSetOper.expireAt(DateUtil.getEndOfDay(new Date()));
                }
            }else{
                throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1000.getErrorNo(), "无法获取用户每日挂售金额汇总记录锁[" + tradeEntrust.getUserId() + "]");
            }
        }finally{
            redisLock.releaseLock(createLockKey);
        }
    }

    @Override
    public Long getUserSellAmountFromCache(Long userId) {
        return getDataFromCache(userId,YYT_SELL_AMOUNT_COUNT);

    }

    @Override
    public Long getUserSellMoneyFromCache(Long userId) {
        return getDataFromCache(userId,YYT_SELL_MONEY_COUNT);
    }


    public Long getDataFromCache(Long userId,String cacheKey){
        Long value = 0L;
        BoundZSetOperations<String,Object> zSetOper = redisTemplate.boundZSetOps(cacheKey);
        if (redisTemplate.hasKey(cacheKey)){
            Double count = zSetOper.score(userId);
            if (count != null){
                value = count.longValue();
            }
        }else{
            //不存在则初始化缓存
            if (cacheKey.equals(YYT_SELL_AMOUNT_COUNT)){
                value = initUserEntrustTimeCache(YYT_SELL_AMOUNT_COUNT,userId,0L);
            }else if (cacheKey.equals(YYT_SELL_MONEY_COUNT)){
                value = initUserEntrustMoneyCache(YYT_SELL_MONEY_COUNT,userId,0L);
            }
        }
        return value;
    }

    @Override
    public Boolean isUserSellAmountMeetsLimit(Long userId,Long thisAmount) {
        Long amount = this.getUserSellAmountFromCache(userId) + thisAmount;
        Long sellAmountLimit = BusinessParamHelper.getLongValue(bussinessParamService,EnumBussinessParam.USER_SELL_AMOUNT_LIMIT,1000L);
        if (amount > sellAmountLimit){
            return false;
        }else {
            return true;
        }
    }

    @Override
    public Boolean isUserSellMoneyMeetsLimit(Long userId,Long thisAmount) {
        Long amount = this.getUserSellMoneyFromCache(userId) + thisAmount;
        Long sellMoneyLimit = BusinessParamHelper.getLongValue(bussinessParamService,EnumBussinessParam.USER_SELL_MONEY_LIMIT,1000L);
        sellMoneyLimit = sellMoneyLimit * 100;
        if (amount > sellMoneyLimit){
            return false;
        }else {
            return true;
        }
    }

    //初始化用户当日挂售次数缓存
    protected Long initUserEntrustTimeCache(String cacheKey,Long userId,Long times){
        String initCacheLockKey = new StringBuilder(cacheKey).append("_LOCK").toString();
        try {
            Long amount = 0L;
            if (redisLock.lock(initCacheLockKey)) {
                BoundZSetOperations<String,Object> zSetOper = redisTemplate.boundZSetOps(cacheKey);
                //db取到用户当日已经挂售的次数
                TradeEntrustQuery query = new TradeEntrustQuery();
                query.setUserId(userId);
                Map<String,Long> dataMap = tradeEntrustService.getUserDaliyEntrustTimeAndMoney(query);
                amount = dataMap.get("entrustTimes") + times;
                zSetOper.add(userId,amount);
                //设置缓存的过期时间为当天
                zSetOper.expireAt(DateUtil.getEndOfDay(new Date()));
            }
            return amount;
        } finally {
            redisLock.releaseLock(initCacheLockKey);
        }
    }

    //初始化用户当日挂售金额缓存
    protected Long initUserEntrustMoneyCache(String cacheKey,Long userId,Long EntrustMoney){
        String initCacheLockKey = new StringBuilder(cacheKey).append("_LOCK").toString();
        try {
            Long amount = 0L;
            if (redisLock.lock(initCacheLockKey)) {
                BoundZSetOperations<String,Object> zSetOper = redisTemplate.boundZSetOps(cacheKey);
                //db取到用户当日挂售金额总数
                TradeEntrustQuery query = new TradeEntrustQuery();
                query.setUserId(userId);
                Map<String,Long> dataMap = tradeEntrustService.getUserDaliyEntrustTimeAndMoney(query);
                amount = dataMap.get("entrustMoney") + EntrustMoney;
                zSetOper.add(userId,amount);
                //设置缓存的过期时间为当天
                zSetOper.expireAt(DateUtil.getEndOfDay(new Date()));
            }
            return amount;
        } finally {
            redisLock.releaseLock(initCacheLockKey);
        }
    }
}
